// 电影仓储模块
module repository.MovieRepo;

import std.format;
import d2sqlite3;
import model.Movie;
import model.MovieVlink;
import utils.ConstValue;

// 电影仓储类
class MovieRepo
{
    Database db;
    this ()
    {
        db = Database(Const.connStr);
    }

    ~this ()
    {
        db.close();
    }

    /** 
     * 添加电影
     * Params:
     *   movie   Movie   Movie实例
     * Returns: bool
     */
    bool addMovie (Movie movie)
    {
        Statement statement1 = db.prepare("SELECT m.id FROM movie m WHERE m.id = :id LIMIT 1;");
        statement1.bind(":id", movie.id);
        ResultRange res = statement1.execute();
        if (!res.empty)
        {
            return true;
        }

        Statement statement2 = db.prepare("INSERT INTO movie (id, name, url, category, region, year, actors, director, intro, img, comment) VALUES (:id, :name, :url, :category, :region, :year, :actors, :director, :intro, :img, :comment)");
        statement2.inject(movie.id, movie.name, movie.url, movie.category, movie.region, movie.year, movie
                .actors, movie.director, movie.intro, movie.img, movie.comment);
        return db.changes > 0;
    }

    /** 
     * 批量添加电影
     * Params:
     *   movieList   Movie[]    待添加的电影列表
     * Returns: bool
     */
    bool addMovieBatch (Movie[] movieList)
    {
        import std.format : format;

        auto total = movieList.length;
        string sql = "INSERT INTO movie (id, name, url, category, region, year, actors, director, intro, img, comment) VALUES ";
        string sqlLeft;
        foreach (m; movieList)
        {
            sqlLeft = format(`("%s","%s","%s","%s","%s",%d,"%s","%s","%s","%s","%s")`,
                m.id, m.name, m.url, m.category, m.region, m.year,
                m.actors, m.director, m.intro, m.img, m.comment);
            sql ~= sqlLeft;
        }
        sql ~= ";";

        db.execute(sql);
        int ch = db.changes;
        if (0 < ch && ch <= total)
        {
            return true;
        }
        return false;
    }

    /** 
     * 删除电影
     * Params:
     *   movieId    string    id值
     * Returns: bool
     */
    bool removeMovie (string movieId)
    {
        Statement statement = db.prepare("DELETE FROM movie WHERE id=:id");
        statement.inject(movieId);
        return db.changes > 0;
    }

    /** 
    * 更新电影信息
    * Params:
    *   movieId    string    id值
    *   movie    Movie   Movie实例
    * Returns: bool
    */
    bool updateMovie (string movieId, Movie movie)
    {
        Statement statement = db.prepare("UPDATE movie SET name=:name, url=:url, category=:category, region=:region, year=:year, actors=:actors, director=:director, intro=:intro, img=:img, comment=:comment WHERE id=:id");
        statement.inject(movie.name, movie.url, movie.category, movie.region, movie.year, movie
                .actors, movie
                .director, movie.intro, movie.img, movie.comment, movieId);
        return db.changes > 0;
    }

    /** 
     * 获取电影列表数据
     * Returns: Movie[]
     */
    Movie[] getMovieList ()
    {
        ResultRange results = db.execute(
            "SELECT id, name, url, category, region, year, actors, director, intro, img, comment FROM movie ORDER BY year DESC");
        Movie[] movieList = [];
        if (results.empty)
        {
            return movieList;
        }

        foreach (Row row; results)
        {
            auto id = row["id"].as!string;
            auto name = row["name"].as!string;
            auto url = row["url"].as!string;
            auto category = row["category"].as!string;
            auto region = row["region"].as!string;
            auto year = row["year"].as!uint;
            auto actors = row["actors"].as!string;
            auto director = row["director"].as!string;
            auto intro = row["intro"].as!string;
            auto img = row["img"].as!string;
            auto comment = row["comment"].as!string;

            movieList ~= new Movie(id, name, url, category, region, year, actors, director, intro, img, comment);
        }

        return movieList;
    }

    /** 
     * 分页获取电影列表数据
     * Params:
     *   pageSize    uint    页大小
     *   pageNum    uint    页码
     * Returns: Movie[]
     */
    Movie[] getMovieList (uint pageSize, uint pageNum)
    {
        if (pageSize <= 4)
        {
            pageSize = 8;
        }
        if (pageNum <= 0)
        {
            pageNum = 1;
        }
        uint offset = (pageNum - 1) * pageSize;
        Statement statement = db.prepare("SELECT id, name, url, category, region, year, actors, director, intro, img, comment FROM movie as t ORDER BY t.year DESC LIMIT :pageSize OFFSET :offset;");
        statement.bindAll(pageSize, offset);
        ResultRange results = statement.execute();
        scope (exit)
        {
            statement.reset();
        }

        Movie[] movieList = [];
        if (results.empty)
        {
            return movieList;
        }

        foreach (Row row; results)
        {
            auto id = row["id"].as!string;
            auto name = row["name"].as!string;
            auto url = row["url"].as!string;
            auto category = row["category"].as!string;
            auto region = row["region"].as!string;
            auto year = row["year"].as!uint;
            auto actors = row["actors"].as!string;
            auto director = row["director"].as!string;
            auto intro = row["intro"].as!string;
            auto img = row["img"].as!string;
            auto comment = row["comment"].as!string;

            movieList ~= new Movie(id, name, url, category, region, year, actors, director, intro, img, comment);
        }

        return movieList;
    }

    /** 
     * 获取总记录数
     * Returns: uint
     */
    uint getTotalCount ()
    {
        uint total = db.execute("SELECT COUNT(id) FROM movie;").oneValue!uint;
        return total;
    }

    /** 
     * 获取一个电影
     * Params:
     *   movieId    string    id值
     * Returns: Movie
     */
    Movie getOneMovie (string movieId)
    {
        Statement statement = db.prepare(
            "SELECT id, name, url, category, region, year, actors, director, intro, img, comment FROM movie WHERE id=:id LIMIT 1");

        statement.bind(":id", movieId);
        ResultRange results = statement.execute();
        // writeln(results.front);
        scope (exit)
        {
            statement.reset();
        }

        if (results.empty)
        {
            return null;
        }
        auto row = results.front;
        auto id = row["id"].as!string;
        auto name = row["name"].as!string;
        auto url = row["url"].as!string;
        auto category = row["category"].as!string;
        auto region = row["region"].as!string;
        auto year = row["year"].as!uint;
        auto actors = row["actors"].as!string;
        auto director = row["director"].as!string;
        auto intro = row["intro"].as!string;
        auto img = row["img"].as!string;
        auto comment = row["comment"].as!string;

        return new Movie(id, name, url, category, region, year, actors, director, intro, img, comment);
    }

    /** 
     * 获取某个电影的集数链接列表
     * Params:
     *   movieId    string    电影id值
     * Returns: MovieVlink[]
     */
    MovieVlink[] getMovieVideoLinks (string movieId)
    {
        Statement statement = db.prepare(
            "SELECT id, name, url, real_url FROM movie_vlinks WHERE movie_id=:id");
        statement.bind(":id", movieId);
        ResultRange results = statement.execute();
        scope (exit)
        {
            statement.reset();
        }

        MovieVlink[] list = [];
        if (results.empty)
        {
            return list;
        }

        foreach (Row row; results)
        {
            auto id = row["id"].as!uint;
            auto name = row["name"].as!string;
            auto url = row["url"].as!string;
            auto real_url = row["real_url"].as!string;

            list ~= new MovieVlink(id, name, url, real_url);
        }

        return list;
    }

    /** 
     * 获取电影全部年份
     * Returns: uint[]
     */
    uint[] getMovieYears ()
    {
        uint[] years = [];
        ResultRange results = db.execute("SELECT DISTINCT year FROM movie;");
        if (results.empty)
        {
            return years;
        }
        foreach (Row row; results)
        {
            uint year = row["year"].as!uint;
            years ~= year;
        }

        return years;
    }

    /** 
     * 写评语
     * Params:
     *   id = string
     *   comment = string
     * Returns: bool
     */
    bool doComment (string id, string comment)
    {
        Statement statement = db.prepare("UPDATE teleplay SET comment=:comment WHERE id=:id");
        statement.bind(":comment", comment);
        statement.bind(":id", id);
        statement.execute();
        return db.changes > 0;
    }
}
